﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Xml;
using System.Data;
using System.Data.Common;

namespace Skywave.Security
{
    public enum UserManagementTables
    {
        Users,
        Groups,
        Policies,
        PolicyValues_Int,
        PolicyValues_String,
        User_Groups
    }
    public class UserManagement
    {
        UserManagementDataContext dcUM;
        public UserManagement(string sqlConnectionString)
        {
            _ConnectionString = sqlConnectionString;
            dcUM = new UserManagementDataContext(sqlConnectionString);
        }
        public UserManagement(DbConnection cnToUse)
        {
            dcUM = new UserManagementDataContext(cnToUse);
        }
        private string _ConnectionString = "";

        /// <summary>
        /// If you specify a "TableName" for a table, it will be used for that table and if not, the equivalent name for enum will be used
        /// </summary>
        public Dictionary<UserManagementTables, string> TableNames
        {
            get { return _TableNames; }
            set { _TableNames = value; }
        }
        private Dictionary<UserManagementTables, string> _TableNames = new Dictionary<UserManagementTables, string>();

        private Dictionary<string, PolicyDescriptor> mRegisteredPolicies = new Dictionary<string, PolicyDescriptor>();
        /// <summary>
        /// RegisteredPolicies Property
        /// </summary>
        public Dictionary<string, PolicyDescriptor> RegisteredPolicies
        {
            get { return mRegisteredPolicies; }
        }

        private List<PolicyDescriptor> _RegisteredPoliciesList = new List<PolicyDescriptor>();
        /// <summary>
        /// All policies registered - Not in parent child mode like RegisteredPolicies property
        /// </summary>
        public List<PolicyDescriptor> RegisteredPoliciesList
        {
            get { return _RegisteredPoliciesList; }
        }

        private Dictionary<string, int> _RegisteredIssuers = new Dictionary<string, int>();
        /// <summary>
        /// RegisteredIssuers Property
        /// </summary>
        public Dictionary<string, int> RegisteredIssuers
        {
            get { return _RegisteredIssuers; }
        }

        public int RegisterIssuer(string issuerUniqueId)
        {
            if (!_RegisteredIssuers.ContainsKey(issuerUniqueId))
            {
                Issuer issuer1 = (from x1 in dcUM.Issuers
                                  where x1.UniqueId == issuerUniqueId
                                  select x1).FirstOrDefault();
                if (issuer1 == null)
                {
                    issuer1 = new Issuer();
                    issuer1.UniqueId = issuerUniqueId;
                    dcUM.Issuers.InsertOnSubmit(issuer1);
                    dcUM.SubmitChanges();
                }
                _RegisteredIssuers.Add(issuerUniqueId, issuer1.Id);
            }
            return _RegisteredIssuers[issuerUniqueId];
        }
        public void RegisterPolicies(string issuerUniqueId, string xmlFilePath)
        {
            XmlReader xmlR1 = System.Xml.XmlReader.Create(xmlFilePath);
            RegisterPolicies(issuerUniqueId, xmlR1);
        }
        public void RegisterPolicies(string issuerUniqueId, System.IO.Stream xmlFileStream)
        {
            XmlReader xmlR1 = System.Xml.XmlReader.Create(xmlFileStream);
            RegisterPolicies(issuerUniqueId, xmlR1);
        }
        public void RegisterPolicies(string issuerUniqueId, XmlReader reader)
        {
            int issuerId = RegisterIssuer(issuerUniqueId);
            int curDepth = 0;
            PolicyDescriptor pdParent = new PolicyDescriptor();
            PolicyDescriptor pdStart = pdParent;
            PolicyDescriptor pdLast = null;

            while (!reader.EOF)
            {
                reader.Read();
                if (reader.IsStartElement())
                {
                    if (reader.Name == "Folder" || reader.Name == "Policy")
                    {
                        if (reader.Depth != curDepth)
                        {
                            if (reader.Depth > curDepth)
                            {
                                if (pdLast != null) pdParent = pdLast;
                            }
                            else
                            {
                                pdParent = pdParent.Parent;
                            }
                            curDepth = reader.Depth;
                        }

                        pdLast = new PolicyDescriptor();
                        pdLast.Text = reader.GetAttribute("Text");
                        pdLast.IssuerId = issuerId;
                        pdLast.IssuerUniqueId = issuerUniqueId;
                        if (reader.Name == "Policy")
                        {
                            pdLast.Name = reader.GetAttribute("Name");
                            pdLast.InterfaceType = (PolicyInterfaceTypes)(int.Parse(reader.GetAttribute("InterfaceType")));
                            pdLast.ValueType = (PolicyValueTypes)(int.Parse(reader.GetAttribute("ValueType")));
                            pdLast.ReflectionType = (string.IsNullOrEmpty(reader.GetAttribute("ReflectionType"))) ?
                                PolicyValueReflectionType.Int : (PolicyValueReflectionType)int.Parse(reader.GetAttribute("ReflectionType"));
                            pdLast.TargetType = (string.IsNullOrEmpty(reader.GetAttribute("TargetType"))) ?
                                PolicyTargetTypes.Application : (PolicyTargetTypes)int.Parse(reader.GetAttribute("TargetType"));
                            pdLast.Description = reader.GetAttribute("Description");
                            pdLast.DefaultValue = reader.GetAttribute("DefaultValue");
                        }
                        else if (reader.Name == "Folder")
                        {
                            pdLast.InterfaceType = PolicyInterfaceTypes.Folder;
                            pdLast.ValueType = PolicyValueTypes.NoValue;
                            pdLast.Description = "";
                            pdLast.DefaultValue = "";
                        }
                        pdLast.Parent = pdParent;
                        pdParent.Childs.Add(pdLast);
                    }
                }
                else //it is an ending tag so do nothing
                {
                    if (reader.Name == "Folder")
                    {
                        if (reader.Depth != curDepth)
                        {
                            if (reader.Depth > curDepth)
                            {
                                if (pdLast != null) pdParent = pdLast;
                            }
                            else
                            {
                                pdParent = pdParent.Parent;
                            }
                            curDepth = reader.Depth;
                        }
                    }
                }
            }
            reader.Close();
            if (mRegisteredPolicies.ContainsKey(issuerUniqueId))
                mRegisteredPolicies[issuerUniqueId] = pdStart;
            else
                mRegisteredPolicies.Add(issuerUniqueId, pdStart);

            RegisterPoliciesInDbRecursive(pdStart);
        }
        private void RegisterPoliciesInDbRecursive(PolicyDescriptor policyDescriptor)
        {
            if (policyDescriptor.InterfaceType != PolicyInterfaceTypes.Folder)
            {
                Policy policy1 = (from x1 in dcUM.Policies
                                  where x1.IssuerId == policyDescriptor.IssuerId && x1.PolicyName == policyDescriptor.Name
                                  select x1).FirstOrDefault();
                if (policy1 == null)
                {
                    policy1 = new Policy();
                    policy1.IssuerId = policyDescriptor.IssuerId;
                    policy1.PolicyName = policyDescriptor.Name;
                    policy1.InterfaceTypeDevId = (int)policyDescriptor.InterfaceType;
                    policy1.ValueTypeDevId = (int)policyDescriptor.ValueType;
                    policy1.ReflectionTypeDevId = (int)policyDescriptor.ReflectionType;
                    policy1.TargetDevId = (int)policyDescriptor.TargetType;
                    dcUM.Policies.InsertOnSubmit(policy1);
                    dcUM.SubmitChanges();
                }
                policyDescriptor.PolicyId = policy1.Id;
                //
                _RegisteredPoliciesList.Add(policyDescriptor);
            }
            foreach (PolicyDescriptor pd1 in policyDescriptor.Childs)
            {
                RegisterPoliciesInDbRecursive(pd1);
            }
        }

        public string GetIssuerUniqueId(int issuerId)
        {
            if (!_RegisteredIssuers.ContainsValue(issuerId))
            {
                Issuer issuer1 = (from x1 in dcUM.Issuers
                                  where x1.Id == issuerId
                                  select x1).FirstOrDefault();
                if (issuer1 == null)
                    throw new ArgumentException(string.Format("The Issuer with IssuerId={0} is not registered.", issuerId));
                else
                    _RegisteredIssuers.Add(issuer1.UniqueId, issuer1.Id);
            }
            return (from x1 in _RegisteredIssuers
                    where x1.Value == issuerId
                    select x1.Key).FirstOrDefault();
        }
        public int GetIssuerId(string issuerUniqueId)
        {
            if (!_RegisteredIssuers.ContainsKey(issuerUniqueId))
            {
                Issuer issuer1 = (from x1 in dcUM.Issuers
                                  where x1.UniqueId == issuerUniqueId
                                  select x1).FirstOrDefault();
                if (issuer1 == null)
                    throw new ArgumentException(string.Format("The Issuer with UniqueId={0} is not registered.", issuerUniqueId));
                else
                    _RegisteredIssuers.Add(issuerUniqueId, issuer1.Id);
            }
            return _RegisteredIssuers[issuerUniqueId];
        }
        public int GetPolicyId(string issuerUniqueId, string policyName)
        {
            return GetPolicyId(GetIssuerId(issuerUniqueId), policyName);
        }
        public int GetPolicyId(int issuerId, string policyName)
        {
            int? r = (from x1 in dcUM.Policies
                      where x1.IssuerId == issuerId && x1.PolicyName == policyName
                      select x1.Id).FirstOrDefault();
            if (r == null)
                throw new ArgumentException(string.Format("Policy with IssuerId={0} and PolicyName={1} is not registered.", issuerId, policyName));
            else
                return r.Value;
        }

        public object GetAppliedPolicy(string userName, string issuerUniqueId, string policyName, bool isAdditive, int valueTargetId, int userGroupTargetId)
        { return GetAppliedPolicy(userName, GetPolicyId(issuerUniqueId, policyName), isAdditive, valueTargetId, userGroupTargetId); }
        public object GetAppliedPolicy(string userName, int issuerId, string policyName, bool isAdditive, int valueTargetId, int userGroupTargetId)
        { return GetAppliedPolicy(userName, GetPolicyId(issuerId, policyName), isAdditive, valueTargetId, userGroupTargetId); }
        public object GetAppliedPolicy(string userName, int policyId, bool isAdditive, int valueTargetId, int userGroupTargetId)
        {
            User user1 = (from x2 in dcUM.Users
                          where x2.UserName.ToLower() == userName.ToLower()
                          select x2).FirstOrDefault();
            return GetAppliedPolicy(user1, policyId, isAdditive, valueTargetId, userGroupTargetId);
        }
        public object GetAppliedPolicy(int userId, string issuerUniqueId, string policyName, bool isAdditive, int valueTargetId, int userGroupTargetId)
        { return GetAppliedPolicy(userId, GetPolicyId(issuerUniqueId, policyName), isAdditive, valueTargetId, userGroupTargetId); }
        public object GetAppliedPolicy(int userId, int issuerId, string policyName, bool isAdditive, int valueTargetId, int userGroupTargetId)
        { return GetAppliedPolicy(userId, GetPolicyId(issuerId, policyName), isAdditive, valueTargetId, userGroupTargetId); }
        public object GetAppliedPolicy(int userId, int policyId, bool isAdditive, int valueTargetId, int userGroupTargetId)
        {
            User user1 = (from x2 in dcUM.Users
                          where x2.Id == userId
                          select x2).FirstOrDefault();
            return GetAppliedPolicy(user1, policyId, isAdditive, valueTargetId, userGroupTargetId);
        }
        private object GetAppliedPolicy(User user1, int policyId, bool isAdditive, int valueTargetId, int userGroupTargetId)
        {
            bool shouldReturnDefault = false;
            object r = null;
            if (user1 == null)
                shouldReturnDefault = true;
            else
            {
                Dictionary<int, object> temp1 = GetAppliedPolicy(new List<User> { user1 }, policyId, isAdditive, valueTargetId, userGroupTargetId);
                if (temp1.ContainsKey(user1.Id))
                {
                    r = temp1[user1.Id];
                }
                else
                    shouldReturnDefault = true;
            }
            if (shouldReturnDefault)
            {
                Policy policy1 = (from x1 in dcUM.Policies
                                  where x1.Id == policyId
                                  select x1).FirstOrDefault();
                if (policy1 == null)
                {
                    throw new ArgumentException(string.Format("The policy with Id={0} is not registered.", policyId));
                }
                //
                switch ((PolicyValueReflectionType)policy1.ReflectionTypeDevId)
                {
                    case PolicyValueReflectionType.String:
                        if (isAdditive)
                            r = new List<string>();
                        else
                            r = null;
                        break;
                    case PolicyValueReflectionType.Int:
                    default:
                        if (isAdditive)
                            r = new List<int>();
                        else
                            r = null;
                        break;
                }
            }
            //
            return r;
        }

        public Dictionary<int, object> GetAppliedPolicy(List<int> userIds, string issuerUniqueId, string policyName, bool isAdditive, int valueTargetId, int userGroupTargetId)
        { return GetAppliedPolicy(userIds, GetPolicyId(issuerUniqueId, policyName), isAdditive, valueTargetId, userGroupTargetId); }
        public Dictionary<int, object> GetAppliedPolicy(List<int> userIds, int policyId, bool isAdditive, int valueTargetId, int userGroupTargetId)
        {
            List<User> users = (from x2 in dcUM.Users
                                where userIds.Contains(x2.Id)
                                select x2).ToList();
            return GetAppliedPolicy(users, policyId, isAdditive, valueTargetId, userGroupTargetId);
        }
        private Dictionary<int, object> GetAppliedPolicy(List<User> users, int policyId, bool isAdditive, int valueTargetId, int userGroupTargetId)
        {
            Dictionary<int, object> r = new Dictionary<int, object>();
            Policy policy1 = (from x1 in dcUM.Policies
                              where x1.Id == policyId
                              select x1).FirstOrDefault();
            if (policy1 == null)
            {
                throw new ArgumentException(string.Format("The policy with Id={0} is not registered.", policyId));
            }
            else
            {
                PolicyDescriptor pd1;
                pd1 = (from x1 in RegisteredPoliciesList
                       where x1.PolicyId == policyId
                       select x1).FirstOrDefault();
                if (pd1 == null)
                {
                    pd1 = new PolicyDescriptor()
                    {
                        IssuerId = policy1.IssuerId,
                        IssuerUniqueId = GetIssuerUniqueId(policy1.IssuerId),
                        Name = policy1.PolicyName,
                        PolicyId = policy1.Id,
                        ReflectionType = (PolicyValueReflectionType)policy1.ReflectionTypeDevId,
                        TargetType = (policy1.TargetDevId == null) ? PolicyTargetTypes.Application : (PolicyTargetTypes)policy1.TargetDevId.Value,
                        ValueType = (isAdditive) ? PolicyValueTypes.MultipleValues : PolicyValueTypes.SingleValue
                    };
                }
                //
                switch (pd1.ReflectionType)
                {
                    case PolicyValueReflectionType.Int:
                        foreach (var fe1 in GetAppliedPolicyValues<int>(users, new List<PolicyDescriptor>() { pd1 }, valueTargetId, userGroupTargetId))
                        {
                            if (fe1.Value.Count > 0)
                            {
                                switch (pd1.ValueType)
                                {
                                    case PolicyValueTypes.MultipleValues:
                                        r.Add(fe1.Key, fe1.Value.First().AppliedValueList);
                                        break;
                                    case PolicyValueTypes.SingleValue:
                                    case PolicyValueTypes.NoValue:
                                    default:
                                        r.Add(fe1.Key, fe1.Value.First().AppliedValue);
                                        break;
                                }
                            }
                        }
                        break;
                    case PolicyValueReflectionType.String:
                        foreach (var fe1 in GetAppliedPolicyValues<string>(users, new List<PolicyDescriptor>() { pd1 }, valueTargetId, userGroupTargetId))
                        {
                            if (fe1.Value.Count > 0)
                            {
                                switch (pd1.ValueType)
                                {
                                    case PolicyValueTypes.MultipleValues:
                                        r.Add(fe1.Key, fe1.Value.First().AppliedValueList);
                                        break;
                                    case PolicyValueTypes.SingleValue:
                                    case PolicyValueTypes.NoValue:
                                    default:
                                        r.Add(fe1.Key, fe1.Value.First().AppliedValue);
                                        break;
                                }
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
            return r;
        }

        public Dictionary<int, List<Security.PolicyAppliedValue<T>>> GetAppliedPolicyValues<T>(List<int> userIds, int valueTargetId, int userGroupTargetId)
        { return GetAppliedPolicyValues<T>(userIds, RegisteredPoliciesList, valueTargetId, userGroupTargetId); }
        public Dictionary<int, List<Security.PolicyAppliedValue<T>>> GetAppliedPolicyValues<T>(List<int> userIds, List<PolicyDescriptor> policies, int valueTargetId, int userGroupTargetId)
        {
            List<User> users = (from x2 in dcUM.Users
                                where userIds.Contains(x2.Id)
                                select x2).ToList();
            return GetAppliedPolicyValues<T>(users, policies, valueTargetId, userGroupTargetId);
        }

        private static object lock_GetAppliedPolicyValues = new object();
        private Dictionary<int, List<Security.PolicyAppliedValue<T>>> GetAppliedPolicyValues<T>(List<User> users, List<PolicyDescriptor> policies, int valueTargetId, int userGroupTargetId)
        {
            lock (lock_GetAppliedPolicyValues)
            {
                Dictionary<int, List<Security.PolicyAppliedValue<T>>> r = new Dictionary<int, List<PolicyAppliedValue<T>>>();
                //
                T tempType1 = default(T);
                //
                if (tempType1 is string)
                    policies = policies.Where(q => q.ReflectionType == PolicyValueReflectionType.String).ToList();
                else if (tempType1 is int)
                    policies = policies.Where(q => q.ReflectionType == PolicyValueReflectionType.Int).ToList();
                else
                    throw new ArgumentException("Type of T is unsupported: The supported types for T are: string, int");
                //
                //Type tType = tempType1.GetType();
                //System.ComponentModel.TypeConverter tTypeConverter = System.ComponentModel.TypeDescriptor.GetConverter(tType);

                //Return empty if no user found or user is disabled
                List<int> userIds = new List<int>();
                if (users != null)
                    userIds = (from x1 in users
                               where
                                x1 != null &&

                                x1.IsDisabled == null || x1.IsDisabled == false
                               select x1.Id).ToList();
                //
                if (userIds.Count > 0)
                {
                    foreach (PolicyDescriptor policy1 in policies)
                    {
                        switch (policy1.TargetType)
                        {
                            case PolicyTargetTypes.Application:
                                valueTargetId = -1;
                                break;
                            case PolicyTargetTypes.Archive:
                                break;
                            default:
                                break;
                        }
                        //
                        switch (policy1.ReflectionType)
                        {
                            case PolicyValueReflectionType.String:
                                foreach (var fe1 in from y1 in
                                                        (from x1 in dcUM.PolicyValues_Strings
                                                         join j1 in dcUM.User_Groups on new { x1.OwnerDevId, GroupId = x1.OwnerId } equals new { OwnerDevId = 2, j1.GroupId } into gj1
                                                         from x2 in gj1.DefaultIfEmpty()
                                                         where
                                                              (x1.IsRemoved == false && x1.PolicyId == policy1.PolicyId && x1.TargetId == valueTargetId)
                                                              &&
                                                              (x2 == null || x2.TargetId == -1 || x2.TargetId == userGroupTargetId)
                                                              &&
                                                              (
                                                                  (x1.OwnerDevId == 1 && userIds.Contains(x1.OwnerId))
                                                                  ||
                                                                  (x1.OwnerDevId == 2 && x2 != null && userIds.Contains(x2.UserId))
                                                              )
                                                         select new { PolicyValue = x1, UserId = (x1.OwnerDevId == 2) ? ((x2 == null) ? -1 : x2.UserId) : x1.OwnerId })
                                                    group y1 by y1.UserId into g1
                                                    select new { UserId = g1.Key, Values = g1.ToList() })
                                {
                                    if (!r.ContainsKey(fe1.UserId))
                                        r.Add(fe1.UserId, new List<PolicyAppliedValue<T>>());
                                    //
                                    if (policy1.ValueType == PolicyValueTypes.MultipleValues)
                                        r[fe1.UserId].Add(new Security.PolicyAppliedValue<T>()
                                        {
                                            Policy = policy1,
                                            AppliedValueList = (from x1 in fe1.Values
                                                                select (T)((object)x1.PolicyValue.Value)).Distinct().ToList()
                                        });
                                    else
                                    {
                                        var valueId = (from x1 in fe1.Values
                                                       where x1.PolicyValue.OwnerDevId == 1
                                                       select x1).FirstOrDefault();
                                        if (valueId == null)
                                        {
                                            valueId = (from x1 in fe1.Values
                                                       select x1).FirstOrDefault();
                                        }
                                        r[fe1.UserId].Add(new PolicyAppliedValue<T>()
                                        {
                                            Policy = policy1,
                                            AppliedValue = (valueId == null) ? default(T) : (T)((object)valueId.PolicyValue.Value)
                                        });
                                    }

                                }
                                break;
                            case PolicyValueReflectionType.Int:
                            default:
                                foreach (var fe1 in from y1 in
                                                        (from x1 in dcUM.PolicyValues_Ints
                                                         join j1 in dcUM.User_Groups on new { x1.OwnerDevId, GroupId = x1.OwnerId } equals new { OwnerDevId = 2, j1.GroupId } into gj1
                                                         from x2 in gj1.DefaultIfEmpty()
                                                         where
                                                              (x1.IsRemoved == false && x1.PolicyId == policy1.PolicyId && x1.TargetId == valueTargetId)
                                                              &&
                                                              (x2 == null || x2.TargetId == -1 || x2.TargetId == userGroupTargetId)
                                                              &&
                                                              (
                                                                  (x1.OwnerDevId == 1 && userIds.Contains(x1.OwnerId))
                                                                  ||
                                                                  (x1.OwnerDevId == 2 && x2 != null && userIds.Contains(x2.UserId))
                                                              )
                                                         select new { PolicyValue = x1, UserId = (x1.OwnerDevId == 2) ? ((x2 == null) ? -1 : x2.UserId) : x1.OwnerId })
                                                    group y1 by y1.UserId into g1
                                                    select new { UserId = g1.Key, Values = g1.ToList() })
                                {
                                    if (!r.ContainsKey(fe1.UserId))
                                        r.Add(fe1.UserId, new List<PolicyAppliedValue<T>>());
                                    //
                                    if (policy1.ValueType == PolicyValueTypes.MultipleValues)
                                        r[fe1.UserId].Add(new Security.PolicyAppliedValue<T>()
                                        {
                                            Policy = policy1,
                                            AppliedValueList = (from x1 in fe1.Values
                                                                select (T)((object)x1.PolicyValue.Value)).Distinct().ToList()
                                        });
                                    else
                                    {
                                        var valueId = (from x1 in fe1.Values
                                                       where x1.PolicyValue.OwnerDevId == 1
                                                       select x1).FirstOrDefault();
                                        if (valueId == null)
                                        {
                                            valueId = (from x1 in fe1.Values
                                                       select x1).FirstOrDefault();
                                        }
                                        r[fe1.UserId].Add(new PolicyAppliedValue<T>()
                                        {
                                            Policy = policy1,
                                            AppliedValue = (valueId == null) ? default(T) : (T)((object)valueId.PolicyValue.Value)
                                        });
                                    }

                                }
                                break;
                        }
                    }
                }
                //
                return r;
            }

        }

        private void FillDefaultValues(Dictionary<string, string> issuerAppliedPolicies, PolicyDescriptor policyDescriptor)
        {
            if (policyDescriptor.Name != null && !issuerAppliedPolicies.ContainsKey(policyDescriptor.Name))
            {
                issuerAppliedPolicies.Add(policyDescriptor.Name, policyDescriptor.DefaultValue);
            }
            foreach (PolicyDescriptor fe1 in policyDescriptor.Childs)
            {
                FillDefaultValues(issuerAppliedPolicies, fe1);
            }
        }

        private void AddOrUpdateResault(Dictionary<string, string> resault, PolicyDescriptor pd1, string value, bool isGroup)
        {
            string r = "";
            if (resault.ContainsKey(pd1.Name))
                r = resault[pd1.Name];
            if (isGroup && pd1.InterfaceType == PolicyInterfaceTypes.List)
            {
                if (!r.Contains(value)) r += value;
            }
            else
                r = value;

            if (resault.ContainsKey(pd1.Name))
                resault[pd1.Name] = r;
            else
                resault.Add(pd1.Name, r);
        }

        //public static PolicyDescriptor FindPolicyDescriptor( string issuerUniqueId, string policyName)
        //{
        //    return FindPolicyDescriptorRecursive(mRegisteredPolicies[issuerUniqueId], policyName);
        //}
        //private PolicyDescriptor FindPolicyDescriptorRecursive(PolicyDescriptor policyDescriptor, string policyName)
        //{
        //    PolicyDescriptor resault = null;
        //    if (policyDescriptor.Name == policyName) resault = policyDescriptor;
        //    else
        //    {
        //        foreach (PolicyDescriptor pd1 in policyDescriptor.Childs)
        //        {
        //            resault = FindPolicyDescriptorRecursive(pd1, policyName);
        //            if (resault != null) break;
        //        }
        //    }
        //    return resault;
        //}

        //~UserManagement()
        //{
        //    //if (mConnection != null && mConnection.State == ConnectionState.Open) mConnection.Close();
        //}

        public List<PolicyOwner> GetOwners(List<PolicyValues_Int> list)
        {
            List<PolicyOwner> r = new List<PolicyOwner>();
            //
            IQueryable<PolicyValues_Int> q1 = null;
            foreach (var fe1 in from x1 in list
                                group x1 by x1.PolicyId into g1
                                select new
                                {
                                    PolicyId = g1.Key,
                                    List = g1.ToList()
                                })
            {
                foreach (var fe2 in from x1 in fe1.List
                                    group x1 by x1.TargetId into g1
                                    select new
                                    {
                                        TargetId = g1.Key,
                                        List = g1.ToList()
                                    })
                {
                    var q2 = from x1 in dcUM.PolicyValues_Ints
                             where
                              x1.IsRemoved == false &&
                              x1.PolicyId == fe1.PolicyId &&
                              x1.TargetId == fe2.TargetId
                             select x1;
                    var valuesTyped = (from y1 in fe2.List select y1.Value).ToList();
                    //
                    if (q1 == null)
                    {
                        q1 = q2.Where(q => (from x1 in q2
                                            where
                                                x1.OwnerDevId == q.OwnerDevId &&
                                                x1.OwnerId == q.OwnerId &&
                                                valuesTyped.Contains(x1.Value)
                                            select x1).Count() == valuesTyped.Count);
                    }
                    else
                    {
                        q1 = q1.Union(q2.Where(q => (from x1 in q2
                                                     where
                                                        x1.OwnerDevId == q.OwnerDevId &&
                                                        x1.OwnerId == q.OwnerId &&
                                                        valuesTyped.Contains(x1.Value)
                                                     select x1).Count() == valuesTyped.Count));
                    }
                }
            }
            //
            if (q1 != null)
            {
                foreach (var fe1 in from x1 in q1
                                    join jUser in dcUM.Users on new { x1.OwnerDevId, x1.OwnerId } equals new { OwnerDevId = (int)OwnerTypes.User, OwnerId = jUser.Id } into gjUser
                                    from xUser in gjUser.DefaultIfEmpty()
                                    join jGroup in dcUM.Groups on new { x1.OwnerDevId, x1.OwnerId } equals new { OwnerDevId = (int)OwnerTypes.Group, OwnerId = jGroup.Id } into gjGroup
                                    from xGroup in gjGroup.DefaultIfEmpty()
                                    select new
                                    {
                                        PolicyValue = x1,
                                        User = xUser,
                                        Group = xGroup
                                    })
                {
                    PolicyOwner owner1 = new PolicyOwner();
                    //
                    switch ((OwnerTypes)fe1.PolicyValue.OwnerDevId)
                    {
                        case OwnerTypes.User:
                            if (fe1.User == null || fe1.User.IsDisabled == true)
                                continue;
                            owner1.Text = (fe1.User == null) ? "-" : fe1.User.UserName;
                            break;
                        case OwnerTypes.Group:
                            if (fe1.Group == null)
                                continue;
                            owner1.Text = (fe1.Group == null) ? "-" : fe1.Group.Text;
                            break;
                        default:
                            break;
                    }
                    //
                    owner1.OwnerDevId = fe1.PolicyValue.OwnerDevId;
                    owner1.OwnerId = fe1.PolicyValue.OwnerId;
                    owner1.PolicyValueId = fe1.PolicyValue.Id;
                    //
                    if ((from x1 in r
                         where
                          x1.OwnerDevId == owner1.OwnerDevId &&
                          x1.OwnerId == owner1.OwnerId
                         select x1).Count() == 0)
                        r.Add(owner1);
                }
            }
            //
            return (from x1 in r orderby x1.Type_Text, x1.Text select x1).ToList();
        }
    }
}
